package cn.yto.print.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import cn.yto.print.config.CaffeineCacheConfig;
import cn.yto.print.config.PrintFutureContext;
import cn.yto.print.enums.PluginRegistryEnum;
import cn.yto.print.enums.PrintCmdEnum;
import cn.yto.print.enums.ResponseCodeEnum;
import cn.yto.print.model.dto.PrintCacheDTO;
import cn.yto.print.model.request.PrintTaskRequest;
import cn.yto.print.model.request.WxsphPrintRequest;
import cn.yto.print.model.response.PrintTaskResponse;
import cn.yto.print.model.response.WxsphPrintResponse;
import cn.yto.print.plugins.SocketSessionContext;
import cn.yto.print.service.PrintConsumerService;
import cn.yto.print.service.handle.ITextMessageFunction;
import cn.yto.print.service.handle.MessageHandler;
import cn.yto.print.utils.PrintTaskUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Component
public class WxsphMessageHandler extends MessageHandler {

    private SocketSessionContext socketSessionContext;

    @Override
    public void initialize() {
        socketSessionContext = new SocketSessionContext(PluginRegistryEnum.WXSPH, createMessageHandler());
    }

    @Override
    public ITextMessageFunction createMessageHandler() {
        return (session, message) -> {
            CaffeineCacheConfig.getHeartCache().put(PluginRegistryEnum.WXSPH.getCode(), 1);
            WxsphPrintResponse wxsphPrintResponse;
            try {
                wxsphPrintResponse = JSONUtil.toBean(message.getPayload(), WxsphPrintResponse.class);
            } catch (Exception e) {
                log.error("微信视频号打印组件回执报文解析异常，报文将丢弃~", e);
                return;
            }

            if (StringUtils.isNotEmpty(wxsphPrintResponse.getCommand()) && "getAppInfo".equals(wxsphPrintResponse.getCommand())) {
                return;
            }
            if (StringUtils.isEmpty(wxsphPrintResponse.getRequestID())) {
                return;
            }
            PrintCacheDTO printCache = CaffeineCacheConfig.getPrintCache().getIfPresent(wxsphPrintResponse.getRequestID());
            if (null == printCache) {
                log.error("微信视频号打印任务 TaskID：{} 缓存不存在，报文将丢弃~", wxsphPrintResponse.getRequestID());
                return;
            }
            CaffeineCacheConfig.getPrintCache().invalidate(wxsphPrintResponse.getRequestID());

            PrintTaskResponse printTaskResponse = new PrintTaskResponse();
            printTaskResponse.setCmd(PrintCmdEnum.NOTIFY_PRINT_RESULT.getCmd());
            printTaskResponse.setTaskId(wxsphPrintResponse.getRequestID());
            printTaskResponse.setSessionId(printCache.getSessionId());
            printTaskResponse.setTemplateType(printCache.getTemplateType());
            List<PrintTaskResponse.PrintStatus> printStatusList = Lists.newArrayList();
            for (WxsphPrintResponse.Result result : wxsphPrintResponse.getResults()) {
                PrintTaskResponse.PrintStatus printStatus = new PrintTaskResponse.PrintStatus();
                printStatus.setStatus(result.getSuccess() ? ResponseCodeEnum.SUCCESS.getStatus() : ResponseCodeEnum.FAILURE.getStatus());
                printStatus.setDocumentID(result.getTaskID());
                printStatus.setMsg(result.getFailureReason());
                printStatusList.add(printStatus);
            }
            printTaskResponse.setPrintStatus(printStatusList);
            CompletableFuture<PrintTaskResponse> future = PrintFutureContext.getResponseFuture(wxsphPrintResponse.getRequestID());
            if (null != future) {
                future.complete(printTaskResponse);
            } else {
                PrintConsumerService.handleTimeOutResponse(printTaskResponse);
            }
        };
    }

    @Override
    public WxsphPrintRequest buildPrintRequest(PrintTaskRequest pluginPrintParam) {

        List<WxsphPrintRequest.Task> taskList = new ArrayList<>();
        int firstDocumentNumber = pluginPrintParam.getFirstDocumentNumber() == 0 ? 1 : pluginPrintParam.getFirstDocumentNumber();
        int totalDocumentCount = pluginPrintParam.getTotalDocumentCount() == 0 ? pluginPrintParam.getDocuments().size() : pluginPrintParam.getTotalDocumentCount();
        AtomicInteger atomicFirstDocumentNumber = new AtomicInteger(firstDocumentNumber);
        pluginPrintParam.getDocuments().forEach(doc -> {
            WxsphPrintRequest.Task task = new WxsphPrintRequest.Task();
            task.setTaskID(doc.getDocumentID());
            task.setPrintInfo(doc.getPrintData());
            task.setPrintNum(new WxsphPrintRequest.printNum(atomicFirstDocumentNumber.get(), totalDocumentCount));
            atomicFirstDocumentNumber.incrementAndGet();
            task.setSplitControl(doc.getSplitControl() == null ? 0 : doc.getSplitControl());
            if (!CollectionUtils.isEmpty(doc.getCustomData())) {
                WxsphPrintRequest.CustomInfo customInfo = new WxsphPrintRequest.CustomInfo();
                if (doc.getCustomData().containsKey("data")) {
                    Map<String, Object> customData = Maps.newHashMap();
                    BeanUtil.copyProperties(doc.getCustomData().get("data"), customData);
                    customInfo.setData(customData);
                }
                if (doc.getCustomData().containsKey("templateUrl")) {
                    customInfo.setTemplateUrl((String) doc.getCustomData().get("templateUrl"));
                }
                task.setCustomInfo(customInfo);
            }
            if (!CollectionUtils.isEmpty(doc.getAddData())) {
                task.setExtendData(doc.getAddData());
            }
            taskList.add(task);
        });

        WxsphPrintRequest wxsphPrintRequest = new WxsphPrintRequest();
        wxsphPrintRequest.setCommand("print");
        wxsphPrintRequest.setVersion("2.0");
        wxsphPrintRequest.setRequestID(pluginPrintParam.getTaskId());
        wxsphPrintRequest.setPrinter(pluginPrintParam.getPrinter());
        wxsphPrintRequest.setTaskList(taskList);
        return wxsphPrintRequest;
    }

    @Override
    public CompletableFuture<PrintTaskResponse> processMessage(PrintTaskRequest printParam) {
        WxsphPrintRequest wxsphPrintRequest = buildPrintRequest(printParam);
        socketSessionContext.sendPrintRequest(wxsphPrintRequest);
        PrintTaskUtil.addPrintTaskCache(printParam);
        CompletableFuture<PrintTaskResponse> completableFuture = new CompletableFuture<>();
        PrintFutureContext.addResponseFuture(printParam.getTaskId(), completableFuture);
        return completableFuture;
    }

    @Override
    public SocketSessionContext getSocketContext() {
        return socketSessionContext;
    }

}
